home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Compression
/
Opener
/
Source
/
Controller.m
< prev
next >
Wrap
Text File
|
1993-08-15
|
24KB
|
1,052 lines
/*
* To add new filetypes:
* The file Opener.table is a list of suffix/command pairs
* that are used to identify and unpack various kinds of files.
* You need to edit this table, and add an icon for the new type:
* add ...
* - a line to Opener.table,
* (formerly, new code in Controller.m:unpackFile())
* - a utility in utils/..., and in Makefile.postamble
* - an icon to the TIFF suitcase in Opener.nib
* - suffixes to 'types[]' in - openRequest
* and please mail me improvements if you do.
*
* Michael Hawley
* mike@media-lab.mit.edu
* Copyright (c) MIT Media Laboratory, September 1991
*
* Revisions:
* new color icons
* fixed case-insensitivity problem for archive file creation
* fixed bug where app incorrectly recognized .ps and .eps extensions
* fixed bug where app didn't properly prepare .PS and .PS for Preview
*
* added gz file type
* added arj file type
* method registerWindow:toPort: is obsolete, so treat it so
* reconciled code to NeXTSTEP 3.1
*
* added -removeTmpFiles, to clean up the scratch space.
* added several new types (lzh, arc, zip, etc).
* made it table-driven.
* added kludge to try automatic unpacking of comp.sources material
* added tar.Z-making function.
*
* added preference panel, plus panel and code to permit selecting
* an arbitrary archiving command.
* added monitoring, "suggestion", defaults.
* safe quoting of funny characters in filenames.
* added archive-building commands.
* fixed .tar.z problem
* command output now generally goes to console,
* except "...done" messages, as when building an archive,
* which pop up in a panel.
* added hack in tmp() to fix the problem of "/tmp/O_foo.app"
* directories not opening.
*
* Thanks to Garance Drosehn (gad@eclipse.its.rpi.edu) for some
* of these improvements.
*/
#include <sys/types.h>
#include <sys/stat.h>
#import <dpsclient/dpsclient.h>
#include <ctype.h>
#import "Controller.h"
#import "DefaultHandler.h"
#import "DirPanel.h"
#import "Process.h"
@implementation Controller
id _defaults;
extern char TmpDir[];
int
err(a,b,c,d) char *a,*b,*c,*d; {
char t[1024];
extern id NXApp;
sprintf(t,a,b,c,d);
return NXRunAlertPanel([NXApp appName],t,0,0,0)==1;
}
static id _pb2, me;
@interface Speaker(ObsoleteMethods)
- (int)registerWindow:(int)windowNum toPort:(port_t)aPort;
- (int)unregisterWindow:(int)windowNum;
@end
- setPackButton2:b {
packButton2 = _pb2 = b;
return self;
}
#include "monitor.m"
char *
tmp(char *s, char *suffix, int isDir) {
/*
* return a path for a temporary file
* named "/tmp/O_[n_]file", where 'file' is 's';
* e.g., /a/b/foo.bar, .bar => /tmp/O_foo
* if 'isDir', map a "." in the suffix to "_" to ensure that
* the directory wrapper will open properly.
*/
static char t[1024];
char *p, u[1024];
int k = 1;
strcpy(u,s);
if (*suffix) u[strlen(u) - strlen(suffix)] = '\0';
if (p = rindex(u,'/')) p++;
else p = s;
if (isDir) {
char *x = rindex(p,'.');
if (x) *x = '_';
}
sprintf(t,"%s/O_%s",TmpDir,p);
while (access(t,0)==0) sprintf(t,"%s/O_%d_%s",TmpDir,k++,p);
return t;
}
char *
path(char *s)
/*
* if 's' is in [NXArgv[0]], return [NXArgv[0]]/s.
* (for looking up internal commands and files in .../Opener.app/...).
*/
{
char t[1024], *q, *r;
static char p[1024];
extern char **NXArgv;
*t = '\0';
sscanf(s,"%s",t);
if (!*t || *t=='(') return s;
r = s + strlen(t);
strcpy(p,*NXArgv);
if (q=rindex(p,'/'))
strcpy(q+1,t);
else
strcpy(p,t);
if (access(p,0)==0){
strcpy(p+strlen(p),r);
return p;
}
return s;
}
char *
skipsp(char *s) {
while (*s==' ' || *s=='\t' || *s == '\n') ++s;
return s;
}
int
blank(char *s) { /* true if 's' is blank */
while (*s == ' ' || *s=='\t' || *s == '\n') ++s;
return !*s;
}
char *
save(char *s) {
char *p = (char *)malloc(strlen(s)+1);
if (p) strcpy(p,s);
return p;
}
void
stripcomment(s) char *s; { /* truncate 's' at a comment character ('#') */
char *p = index(s,'#');
if (p && (p==s || p[-1] != '\\')) *p = '\0';
}
char *
strindex(char *s, char *t) { /* return ptr to first match of 't' in 's' */
int n = strlen(t);
if (s)
while (*s)
if (!strncmp(s, t, n)) return s;
else s++;
return (char *)0;
}
// Case-insensitive version of equal().
// Commented out by Denise Blakeley 08/93 Opener 3.1.1.
// int
// equal(char *s, char *t) { /* true if 's' & 't' are equal (case-insens.) */
// char a, b;
// while (*s && *t){
// a = isupper(*s)? tolower(*s) : *s;
// b = isupper(*t)? tolower(*t) : *t;
// s++, t++;
// if (a != b) return 0;
// }
// return (*s || *t)? 0 : 1;
// }
/* Case-sensitive version of equal(). */
/* Added by Blakeley 08/93 Opener 3.1.1. */
int
equal(char *s, char *t) { /* true if 's' & 't' are equal (case-sens.) */
char a, b;
while (*s && *t){
a = *s;
b = *t;
s++, t++;
if (a != b) return 0;
}
return (*s || *t)? 0 : 1;
}
int
tailmatch(char *s, char *t){ /* true if t appears at end of s */
int tn = strlen(t), sn = strlen(s);
if (tn > sn) return 0;
return equal(s+(sn-tn), t);
}
char *
shstrcat(char *s, char *t){ // strcat, but quote shell metachars
register char *p;
while (*s) s++;
p=t;
if (*p=='~') *s++='\\'; // csh "feature"
while (*p) {
if (*p<=' '||*p>'~'||index(";&()|<>\\'\"$*?[]^!", *p)) *s++='\\';
*s++=*p++;
}
*s='\0';
return t;
}
void
subfname(char *s, char *a, char *b) { /* like 'substr', but assumes the "b"
string is a filename that may need
special-to-shell characters quoted */
char q[8192], quoted_b[2048];
char *p = s;
int n = strlen(a);
quoted_b[0] = '\0';
shstrcat(quoted_b, b);
for (;*p;p++){
if (*p == *a && strncmp(p,a,n)==0){
strcpy(q,p+n);
strcpy(p,quoted_b);
strcpy(p+strlen(quoted_b),q);
p += strlen(quoted_b)-1;
}
}
}
#define MaxLen 256
#define MaxSuf 64
#define MaxTab 64
char Suffix[MaxTab][MaxSuf],
Command[MaxTab][MaxLen];
int NT = 0;
char PSuffix[MaxTab][MaxSuf],
PCommand[MaxTab][MaxLen];
int PNT = 0;
int fdTime(int f){ /* return size of file 'f' */
struct stat b;
fstat(f, &b);
return b.st_mtime;
}
void
clearPackItems() {
int i, n = [[_pb2 target] count];
for (i=0;i<n;i++){
[[_pb2 target] removeItemAt:i];
}
}
void
addPackItem(char *s) {
id c;
c = [[_pb2 target] addItem:s];
[c setTarget:me];
[c setAction:@selector(setPackSuffix:)];
}
void
resetPackItems() {
int i;
clearPackItems();
for (i=0;i<PNT;i++)
addPackItem(PSuffix[i]);
}
void
addUnpackItem(char *s) {
id c;
c = [[_pb2 target] addItem:s];
[c setTarget:me];
[c setAction:@selector(setUnpackSuffix:)];
}
void
loadTable() {
/*
* Unpacking files is table-driven.
* The file "Opener.table" is of the form
* suffix command
* like
* .Z uncompress < $f > $t
* When opening files, the table is checked to
* find a matching command for the given suffix.
*/
char s[1024];
FILE *f;
static int first = 1;
static int t = 0;
int pack = 0;
strcpy(s,path("Opener.table"));
if (!first){
if (f=fopen(s,"r")){
int tt = fdTime(fileno(f));
fclose(f);
if (tt == t) return;
t = tt; // table has changed -- reread it
NT=PNT=0;
clearPackItems();
printf("rereading table\n");
} else
return;
}
first = 0;
if (f = fopen(s,"r")){
char *p, *q;
t = fdTime(fileno(f));
while (fgets(s,sizeof s,f)){
stripcomment(s);
if (blank(s)) continue;
if (strncmp(s,"Unpack:",7)==0) continue;
if (strncmp(s,"Pack:",5)==0){ pack++; continue; }
if (pack){
for (p=skipsp(s), q=PSuffix[PNT];
*p && *p != ' ' && *p != '\t' && (q-PSuffix[PNT])<(MaxSuf-1);
*q++ = *p++) ;
*q = '\0';
for (p = skipsp(p), q=PCommand[PNT];
*p && (*p != '\n') && (q-PCommand[PNT])<(MaxLen-1);
*q++ = *p++) ;
*q='\0';
addPackItem(PSuffix[PNT]);
// printf("[%s]: %s\n",PSuffix[PNT],PCommand[PNT]);
if (!blank(PSuffix[PNT])&& !blank(PCommand[PNT]) && PNT < MaxTab)
++PNT;
} else {
for (p=skipsp(s), q=Suffix[NT];
*p && *p != ' ' && *p != '\t' && (q-Suffix[NT])<(MaxSuf-1);
*q++ = *p++) ;
*q = '\0';
for (p = skipsp(p), q=Command[NT];
*p && (*p != '\n') && (q-Command[NT])<(MaxLen-1);
*q++ = *p++) ;
*q='\0';
// printf("[%s]: %s\n",Suffix[NT],Command[NT]);
if (!blank(Suffix[NT]) && !blank(Command[NT]) && NT < MaxTab)
++NT;
}
}
fclose(f);
} else {
#define C(a,b) strcpy(Suffix[NT],a), strcpy(Command[NT],b), NT++
C(".tar", "unpack: tar xf $f");
C(".shar","unpack: sed '1,/[^:#]/d' $f | /bin/sh");
C(".uu", "unpack: uudecode < $f; open *");
C(".lzh", "unpack: $p/xlharc xf $f");
C(".arc", "unpack: $p/arc ox $f");
C(".sit", "unpack: $p/unsit -u $f");
C(".bin", "unpack: $p/unsit -u $f");
C(".hqx", "unpack: $p/mcvert $f; $p/unsit *.sit.*");
C(".zip", "unpack: $p/unzip $f");
C(".zoo", "unpack: $p/booz x $f");
C(".Z", "uncompress < $f > $t");
#undef C
#define C(a,b) strcpy(PSuffix[PNT],a), strcpy(PCommand[PNT],b), addPackItem(a), PNT++
C(".tar", "(cd $d; tar cf - $F > $t.tar; echo $t.tar done)");
}
}
int
findSuffix(char *s) {
char *p = s + strlen(s);
int i;
loadTable();
for (i=0;i<NT;i++)
if (equal(Suffix[i],p-strlen(Suffix[i])))
/* changed from equal() by Blakeley */
return i;
return -1;
}
int
findPSuffix(char *s) {
char *p = s + strlen(s);
int i;
loadTable();
for (i=0;i<PNT;i++)
if (equal(PSuffix[i],p-strlen(PSuffix[i])))
/* changed from equal() by Blakeley */
return i;
return -1;
}
void
ex_unpack(char *s) {
char t[1024];
if (strncmp(s,"unpack: ",8)) return;
strcpy(t,skipsp(s+8));
strcpy(s,"mkdir $t; cd $t; "); strcat(s,t);
}
void
substr(char *s, char *a, char *b) { /* like 'sub', but with strings */
char q[8192];
char *p = s;
int n = strlen(a);
for (;*p;p++){
if (*p == *a && strncmp(p,a,n)==0){
strcpy(q,p+n);
strcpy(p,b);
strcpy(p+strlen(b),q);
p += strlen(b)-1;
}
}
}
void
expand(char *s, int i, char *c) {
/*
* 's' is the current filename.
* 'i' is the index in the Suffix/Command table.
* 'c' is the command to fill;
* Replace "unpack: ..." with the standard unpack command
* $f with the filename,
* $t with the temp
*/
char *T, *p, S[MaxSuf], q[1024], *r;
int isDir = 0;
strcpy(c,Command[i]);
strcpy(S,s+strlen(s)-strlen(Suffix[i]));
if (strindex(c,"mkdir $t") || strindex(c,"unpack: ")) isDir = 1;
T = tmp(s,Suffix[i],isDir);
ex_unpack(c); /* rewrite "unpack: ..." */
p = c; /* prepend the $p/... paths */
while (p = strindex(p,"$p/")){
sscanf(p,"%s",q);
r = path(q+3);
substr(p,q,r);
}
if (!strindex(c,"open ")){
if (isDir) strcat(c,"; (cd $t; open . )"); // make sure directory opens
else strcat(c,"; open $t");
}
subfname(c,"$f",s); /* expand the abbreviations */
subfname(c,"$t",T);
subfname(c,"$s",S);
}
void
getTmpName(char *s, char *t) {
/*
* Copy a /tmp name for the comp.sources archive into 't'.
* if 's' is ...comp.sources/.../foo/part00.Z ==> /tmp/O_foo
* ...comp.sources/.../foo.Z ==> /tmp/O_foo
*/
char *p = rindex(s,'/'), q[1024], c;
int n;
if (!p) return (void)strcpy(t,s);
strcpy(q,p+1);
c = q[4]; q[4]='\0';
if (equal(q,"part") && isdigit(c)){ /* skip to previous */
*p='\0';
p = rindex(s,'/');
if (!p) p=s;
else p++;
} else p++;
strcpy(t,p);
n = findSuffix(t);
p = (n== -1)? ".Z" : Suffix[n];
if (t[strlen(t)-strlen(p)]=='.')
t[strlen(t)-strlen(p)] = '\0';
strcpy(t,tmp(t,p,0));
}
int
System(fmt, a,b,c,d,e,f,g) char *fmt,*a,*b,*c,*d,*e,*f,*g; {
char t[8192];
sprintf(t,fmt,a,b,c,d,e,f,g);
printf("! %s\n",t);
return system(t);
}
void
openFile(char *s){ /* open 's' in workspace */
int ok = 0;
id p = [NXApp appSpeaker];
[p setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
[p openTempFile:s ok:&ok];
if (!ok) err("Couldn't open file: %s",s);
}
void
previewFile(char *s) { /* open 's' in the default PostScript previewer */
/* This function worked over for 3.1.1 by Blakeley; it never worked before
* but it does now. */
char *a = (char *)0;
char *index;
char head[1024];
int ok = 0;
id p = [NXApp appSpeaker];
/* get handle on the user's favorite Preview application */
if (!a) a = "Preview";
[p setSendPort:NXPortFromName(a, NULL)];
getTmpName(s, head);
index = rindex(&head[0], '.');
if (tailmatch(s, ".PS"))
strcpy(index+1, "ps");
else
strcpy(index+1, "eps");
System("cp %s %s", s, head);
[p openFile: head ok:&ok];
if (!ok) err("Couldn't open file: %s",s);
}
int
confirm(a,b,c,d) char *a,*b,*c,*d; {
char t[1024];
extern id NXApp;
sprintf(t,a,b,c,d);
return NXRunAlertPanel([NXApp appName],t,"Yes","No",NULL)==1;
}
- setTmp:sender {
char *s = (char *)[sender stringValueAt:0];
if (!s || !*s || access(s,0)){
if (s && *s) err("Couldn't access '%s'",s);
[sender setStringValue:TmpDir at:0];
s = (char *)[sender stringValueAt:0];
} else
strcpy(TmpDir,s);
[_defaults writeDefaults:self];
return self;
}
int
unpackFile(s) char *s; {
int i;
char c[2048];
i = findSuffix(s);
if (i != -1){ /* we found a suffix and command in the table */
expand(s,i,c);
[me system:c]; // System("(%s)&",c);
} else
if (tailmatch(s,".PS" ) || tailmatch(s,".EPS")) /* catch some PS files */
previewFile(s);
else
err("Couldn't open '%s'",s);
return 1;
}
- (BOOL)appAcceptsAnotherFile:sender {
return YES;
}
int
isCompSourceArchive(s) char *s; {
return ((strindex(s,"comp.sources") || strindex(s,"mod.sources") ||
strindex(s,"net.sources")) &&
equal(s+strlen(s)-2,".z") &&
!strindex(s,"index") && !strindex(s,"Index") && !strindex(s,"INDEX") &&
!strindex(s,"files") && !strindex(s,"Files") && !strindex(s,"FILES"));
}
#define MaxPend 512
char *Pending[MaxPend];
int NP = 0;
void
reap(DPSTimedEntry n, double now, char *userData){
int i, np;
char x[1024], head[1024], c[8192], *p, q[1024], *r;
DPSRemoveTimedEntry(n);
np = NP;
if (!NP) return;
NP = 0;
if (confirm("Try to build %s...?",Pending[0])){
strcpy(x,Pending[0]);
getTmpName(x,head);
sprintf(c,"(mkdir $t; cp ");
for (i=0; i<np; i++)
strcat(c,Pending[i]), strcat(c," ");
sprintf(c+strlen(c)," $t; $p/builder $t; open $t $t/errors)&");
p = c; /* prepend the $p/... paths */
while (p = strindex(p,"$p/")){
sscanf(p,"%s",q);
r = path(q+3);
substr(p,q,r);
}
substr(c,"$t",head);
System("%s",c);
} else {
for (i=0;i<np;i++)
unpackFile(Pending[i]);
}
for (i=0;i<np;i++) free(Pending[i]);
}
void
pending(s) char *s;
/*
* One or more files from a comp.sources archive are being selected.
* Put them on a queue -- reap() will unpack them specially.
*/
{
if (NP == MaxPend)
return (void)err("Too many pending files! Try quitting.");
Pending[NP++] = save(s);
DPSAddTimedEntry(4.0, (DPSTimedEntryProc)reap, 0, 10);
}
- (int)appOpenFile:(const char *)filename type:(const char *)aType {
me = self;
if (isCompSourceArchive(filename))
pending(filename);
else
unpackFile((char *)filename);
return 1;
}
- openRequest:sender {
const char *directory, *const *files;
static const char *const types[] = {
"tar", "TAR", "tar.z", "tar.Z", "TAR.Z", "tar-z", "tar-Z", "TAR-Z",
"tar.gz", "tar.GZ", "TAR.GZ", "tar-gz", "tar-GZ", "TAR-GZ",
"shar","SHAR","shar.z","shar.Z","SHAR.Z","shar-z","shar-Z","SHAR-Z",
"shar.gz", "shar.GZ", "SHAR.GZ", "shar-gz", "shar-GZ", "SHAR-GZ",
"PS", "EPS", "PS-Z", "ps-Z", "ps-z", "EPS-Z", "eps-Z", "eps-z",
"PS-GZ", "ps-GZ", "ps-gz", "EPS-GZ", "eps-GZ", "eps-gz",
"arc", "Arc", "ARC",
"bin", "Bin", "BIN",
"lzh", "Lzh", "LZH",
"hqx", "Hqx", "HQX",
"sit", "Sit", "SIT",
"zip", "Zip", "ZIP",
"zoo", "Zoo", "ZOO",
"uu", "UU",
"z", "Z",
"gz", "Gz", "GZ",
"arj", "Arj", "ARJ",
"compressed", "Compressed", "COMPRESSED",
NULL};
id p = [[OpenPanel new] allowMultipleFiles:YES];
char name[512];
if ([p runModalForTypes:types]){
files = [p filenames]; // list of multiple files
directory = [p directory];
while (files && *files) {
strcpy(name, directory );
strcat(name, "/" );
strcat(name, *files );
files++;
unpackFile(name);
}
}
return self;
}
- (BOOL)scratchFiles {
char t[1024];
FILE *p;
char s[1024];
BOOL b = NO;
if (strcmp(TmpDir,"/tmp"))
sprintf(t,"ls /tmp/O_* %s/O_*",TmpDir);
else
sprintf(t,"ls /tmp/O_*");
p = popen(t,"r");
if (p){
if (fgets(s,sizeof s,p) && strncmp(s,"No match",8)) b = YES;
pclose(p);
}
return b;
}
- removeTmpFiles:sender {
if ([self scratchFiles] &&
confirm("Remove the scratch files in %s?",TmpDir)){
if (strcmp(TmpDir,"/tmp"))
System("rm -rf /tmp/O_* %s/O_* &",TmpDir);
else
System("rm -rf /tmp/O_* &");
}
return self;
}
- appWillTerminate:sender {
unsigned int wn;
NXConvertWinNumToGlobal([[NXApp appIcon] windowNum], &wn);
[self removeTmpFiles:sender];
[[NXApp appSpeaker] unregisterWindow:wn];
return self;
}
- appDidInit:sender {
char subj[512] = "Opener-";
unsigned int wn;
id s = [NXApp appSpeaker];
me = self;
_defaults = [DefaultHandler new];
[tmpDir setStringValue:TmpDir at:0];
strcat(subj,[version stringValue]);
strcat(subj,"-newuser");
OpenerMonitor(subj);
NXConvertWinNumToGlobal([[NXApp appIcon] windowNum], &wn);
[s setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
[s registerWindow:wn toPort:[[NXApp appListener] listenPort]];
return self;
}
char *iconPathList = (char *)0;
- (int)iconEntered:(int)windowNum at:(double)x :(double)y
iconWindow:(int)iconWindowNum
iconX:(double)iconX iconY:(double)iconY
iconWidth:(double)iconWidth
iconHeight:(double)iconHeight
pathList:(char *)pathList
{
if (!iconPathList || strcmp(iconPathList, pathList)) {
free(iconPathList);
iconPathList = save(pathList);
}
return 0;
}
void
stot(char *s, char **t, char c) { /* split 's' into a table 't' */
char *p;
while (p = index(s,c)){
*p++ = '\0';
*t++ = s;
s = p;
}
*t++ = s;
*t = (char *)0;
}
void
trimdir(char *d, char **t) { /* put longest leading directory of t into d */
int i, n;
char *p,*q;
*d = '\0';
p = rindex(t[0],'/');
if (p){
*p='\0';
strcpy(d,t[0]); strcat(d,"/");
*p='/';
} else return ;
if (t[1]){
for (i=0;t[i];i++){
for (p=d,q=t[i]; *p && *q && *p == *q; p++, q++);
if (!*p) continue;
*p = '\0';
}
}
n = strlen(d);
for (i=0;t[i];i++) t[i] += n;
}
- processOutput:(char *)s {
err("%s",s);
return self;
}
- system:(char *)s { // exec 's' and processOutput pops up a panel with output
[Process new:s delegate:self];
return self;
}
void
pexpand(i,c,d,f,F,t)
char *c, *d, *f, *F, *t;
int i;
/*
* like expand, but for packing:
* 'i' is the index in the Suffix/Command table.
* 'c' is the command to fill;
* 'd' is the prefix directory
* 'F' is the files without 'd' removed
* 'f' is the files with 'd' removed
* 't' is the files with 'd' removed
*/
{
char *p, q[1024], *r;
strcpy(c,PCommand[i]);
p = c; /* prepend the $p/... paths */
while (p = strindex(p,"$p/")){
sscanf(p,"%s",q);
r = path(q+3);
substr(p,q,r);
}
substr(c,"$F",F);
substr(c,"$f",f);
substr(c,"$d",d);
substr(c,"$t",t);
}
void
expand_files(char *s, char *p, char *dir) {
char *t[1024], x[8192];
int i;
strcpy(x,s);
stot(x,t,'\t');
if (dir) trimdir(dir,t);
*p = '\0';
for (i=0;t[i];i++){
if (i > 0) strcat(p," ");
shstrcat(p,t[i]);
p += strlen(p);
}
}
- setDirectory:sender {
id p = [SavePanel new];
char *s;
[[[p contentView]
findViewWithTag:NX_OPTITLEFIELD]
setStringValue:"Unpack files in:"];
if ([p dirPanelRunModal] && (s = (char *)[p directory])){
[tmpDir setStringValue:s at:0];
strcpy(TmpDir,s);
[_defaults writeDefaults:self];
}
return self;
}
static char Files[8192];
char *
getText(id t, char *s) {
id d = [t docView];
int n = [d textLength];
char *p;
*s = '\0';
[d getSubstring:s start:0 length:[d textLength]];
s[n] = '\0';
for (p=s; *p; p++) if (*p == '\n') *p = ' ';
return s;
}
void
setText(id t, char *s) {
id w = [t window], d = [t docView];
static NXPoint origin = {0.0,0.0};
[w disableFlushWindow];
[d setMonoFont:YES];
[d setText:s];
[d setSel:0:999999];
[d setSelGray:0.0];
[d selectNull];
[d scrollPoint:&origin];
[t display];
[[w reenableFlushWindow] flushWindow];
NXPing();
}
int
setSuffixes(char *s) {
char *p = s + strlen(s);
int i, r = -1;
loadTable();
clearPackItems();
for (i=0;i<NT;i++)
if (equal(Suffix[i],p-strlen(Suffix[i]))){
if (r == -1) r = i;
addUnpackItem(Suffix[i]);
}
if (r >= 0) [[_pb2 selectedCell] setTitle:Suffix[r]];
return r;
}
char MoreFiles[8192] = "";
int Reset = 1;
- setPackCommand {
char t[1024], f[4096], F[4096], dir[1024], *p, files[8192];
char c[8192], *curSuffix, *curCmd;
int i;
Again:
curSuffix = (char *)[[packButton2 selectedCell] title];
curCmd = (char *)[[packButton selectedCell] title];
strcpy(files,Files);
if (strcmp(curCmd,"create")==0){
if (Reset) resetPackItems();
Reset = 1;
curSuffix = (char *)[[packButton2 selectedCell] title];
i = findPSuffix(curSuffix);
if (i == -1){
[packPanel orderOut:self];
err("Unknown archive format: %s",curSuffix);
return 0;
}
expand_files(files,f,dir);
expand_files(files,F,0);
sscanf(f,"%s",t); stripnl(t);
if (p = rindex(t,'/')) strcpy(t,p+1);
strcat(t,curSuffix);
p = tmp(t,"",0); strcpy(t,p);
pexpand(i,c,dir,f,F,t);
setText(packCmdText,c);
} else {
if (index(files,'\t')){
char *p;
p = index(files,'\t');
*p = '\0';
strcpy(MoreFiles,p+1);
stripnl(files);
} else {
*MoreFiles = '\0';
}
expand_files(files,f,0);
i = setSuffixes(files);
if (i == -1){
extern void NXBeep();
[[packButton selectedCell] setTitle:"create"];
NXBeep();
resetPackItems();
NXPing();
goto Again;
}
expand(f,i,c);
setText(packCmdText,c);
}
return self;
}
- setPackOrUnpack:sender {
char *s = (char *)[[sender selectedCell] title];
[[packButton selectedCell] setTitle:s];
if (strcmp(s,"create")==0)
[packPanel setTitle:"Make new archive"];
else
[packPanel setTitle:"Unpack archive"];
resetPackItems();
[self setPackCommand];
return self;
}
- setUnpackSuffix:sender {
char *s = (char *)[[sender selectedCell] title];
[[packButton2 selectedCell] setTitle:s];
NXPing();
[self setPackCommand];
return self;
}
- setPackSuffix:sender {
char *s = (char *)[[sender selectedCell] title];
extern char ArchiveFormat[];
strcpy(ArchiveFormat,s);
[_defaults writeDefaults:self];
[[packButton2 selectedCell] setTitle:s];
Reset = 0; // bandaid
NXPing();
[self setPackCommand];
return self;
}
- packFiles:(char *)files {
strcpy(Files,files);
if (!*MoreFiles){
if (index(Files,'\t') || findSuffix(Files) == -1){
[packPanel setTitle:"Make new archive"];
[[packButton selectedCell] setTitle:"create"];
} else {
[packPanel setTitle:"Unpack archive"];
[[packButton selectedCell] setTitle:"unpack"];
}
}
[packPanel makeKeyAndOrderFront:self];
/* Reset = 0; */
[self setPackCommand];
return self;
}
- cancelPack:sender {
[packPanel orderOut:sender];
*MoreFiles = '\0';
return self;
}
- pack:sender {
char c[8192];
getText(packCmdText,c);
if (!blank(c)) [self system:c];
[packPanel orderOut:sender];
if (*MoreFiles) [self packFiles:MoreFiles];
return self;
}
- (int)iconReleasedAt:(double)x :(double)y ok:(int *)flag {
[self packFiles:iconPathList];
*flag = YES;
return 0;
}
- help:sender {
openFile(path("README.rtfd"));
return self;
}
- editTable:sender {
if (confirm("Edit the command table that controls Opener?\n(Unix experts only)"))
System("open %s",path("Opener.table"));
return self;
}
@end